﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Configuration;

using System.Threading;
using System.Net;
using Common.Models;

/*
 * 消息格式:{type}|{clientId}|{content}
 * 
 * */

namespace StockServer
{
    public delegate void OnMsgRecivedDelegate( string msg );
    /// <summary>
    /// 
    /// </summary>
    class AsySocket
    {
        public event OnMsgRecivedDelegate MsgRecivedEvt = null;
        //客户端信息
        public static Dictionary<string, ClientInfo> clients = new Dictionary<string, ClientInfo>();

        public static ManualResetEvent allDone = new ManualResetEvent(false);
        public static ManualResetEvent recieveDone = new ManualResetEvent(false);

        const int backlog = 100;
        Socket m_Socket = null;
        int m_port;
        IPAddress m_ip;

        public bool IsClose = true;
        AsySocket()
        {
            string port = ConfigurationManager.AppSettings["Port"];

            m_ip = IPAddress.Parse(ConfigurationManager.AppSettings["IP"]);
            m_port = int.Parse(port);
        }

    
        AsySocket(Socket linkObject)
        {
            m_Socket = linkObject;

        }
        static AsySocket m_AsySocket;
        static public AsySocket CreateInstance()
        {
            if (m_AsySocket == null)
                m_AsySocket = new AsySocket();
            return m_AsySocket;
        }


        Thread m_listenThread;
        public void BeginListening()
        {
            Init();
            m_Socket.Listen(backlog);
            m_listenThread = new Thread(new ThreadStart(ListenThreadMethod));
            m_listenThread.Start();

        }
        private void Init()
        {  
            IsClose = false;
            m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            m_Socket.Bind(new IPEndPoint(m_ip, m_port));
          
        }
        private void ListenThreadMethod()
        {
            while (!IsClose)
            {
                // Set the event to nonsignaled state.
                allDone.Reset();

                // Start an asynchronous socket to listen for connections.

                Console.WriteLine("开始监听异步连接接入....");
                m_Socket.BeginAccept(
                    new AsyncCallback(AcceptCallBack),
                    m_Socket);

                // Wait until a connection is made before continuing.
                Console.WriteLine("线程等待。。。。。");
                allDone.WaitOne();
            }
        }




        private void AcceptCallBack(IAsyncResult ar)
        {

            
            // Signal the main thread to continue.
            allDone.Set();
            if (IsClose) return;
            Console.WriteLine("开始处理连接接入");
            // Get the socket that handles the client request.
            Socket client = (Socket)ar.AsyncState;
            Console.WriteLine("结束异步接收");
            Socket handler = client.EndAccept(ar);

            // Create the state object.
            StateObject state = new StateObject();
            state.sb = new StringBuilder();
            state.workSocket = handler;
            //用递归方法监听
            Console.WriteLine("开始读信息");
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
            recieveDone.WaitOne();
        }

        void ReadCallback(IAsyncResult ar)
        {
            recieveDone.Set();
            String content = String.Empty;

            // Retrieve the state object and the handler socket
            // from the asynchronous state object.
            Console.WriteLine("读完后的回调处理");
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;

            // Read data from the client socket. 
            int bytesRead = handler.EndReceive(ar);

            if (bytesRead > 0)
            {
                Console.WriteLine("读到信息");
                // There  might be more data, so store the data received so far.
                string msg = Encoding.GetEncoding("GB2312").GetString(
                    state.buffer, 0, bytesRead);
                state.sb.Append(msg);
                Console.WriteLine("从套接字读到 {0} 字节 . \n 内容 : {1}",
                                     msg.Length, msg);
                int result = ProcessMessage(msg, handler);


                // Check for end-of-file tag. If it is not there, read 
                // more data.

                if (result != -1)
                {
                    Console.WriteLine("继续读......");
                    // Not all data received. Get more.
                    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallback), state);
                    recieveDone.WaitOne();

                }
            }
        }

        private int ProcessMessage(string msg, Socket client)
        {
            int result = 0;
            Console.WriteLine("开始处理消息");
            string[] msges = msg.Split('|');
            if (msges != null && msges.Length > 0)
            {
                MsgType type = (MsgType)int.Parse(msges[0]);
                Console.WriteLine("消息类型:" + type.ToString());
                switch (type)
                {
                    case MsgType.Login:
                        ProcessLogin(msges[2], client);
                        break;
                    case MsgType.Exit:
                        ProcessExit(msges[1], client);
                        result = -1;
                        break;
                    case MsgType.ChangePass:
                        ProcessChangePass(msges[1], msges[2], client);
                        break;
                    default:
                        ProcessOtherMsg(msg, client);
                        break;
                }
            }
            if (MsgRecivedEvt != null)
            {
                MsgRecivedEvt(msg);
            }
            return result;
        }

        private void ProcessChangePass(string p, string p_2, Socket client)
        {

        }

        private void ProcessOtherMsg(string msg, Socket client)
        {
            Console.WriteLine("进入其它消息处理");

        }

        private void ProcessExit(string clientId, Socket client)
        {
            client.Close();
            clients.Remove(clientId);
            Console.WriteLine("关闭客户端套接字");
        }

        private void ProcessLogin(string loginInfo, Socket client)
        {

            string[] ms = loginInfo.Split('#');
            Console.WriteLine("收到登录用户信息:" + loginInfo + ms.Length.ToString());
            if (ms == null || ms.Length != 2)
            {
                Send(client, GetMsg("faild", MsgType.Login, ""));
                return;
            }
            string clientId = System.Guid.NewGuid().ToString();
            while (clients.ContainsKey(clientId))
            {
                clientId = System.Guid.NewGuid().ToString();
            }
            ClientInfo ci = new ClientInfo();
            ci.ClientId = clientId;
            ci.ClientSocket = client;
            ci.Password = ms[1];
            ci.UserName = ms[0];


            clients.Add(ci.ClientId, ci);

            Send(client, GetMsg("OK", MsgType.Login, clientId));
            Console.WriteLine("已发送客户端ID:" + clientId);
        }
        string GetMsg(string content, MsgType mtype, string clientId)
        {
            return string.Format("{0}|{1}|{2}", (int)mtype, clientId, content);
        }
        #region 发送
        private static void Send(Socket handler, String data)
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.GetEncoding("GB2312").GetBytes(data);
            Console.WriteLine(string.Format("服务器发出消息:{0}", data));
            // Begin sending the data to the remote device.
            if (handler != null && handler.Connected)
            {
                Console.WriteLine("异步写信息开始");
                handler.BeginSend(byteData, 0, byteData.Length, 0,
                    new AsyncCallback(SendCallback), handler);
            }
            else
            {

                Console.WriteLine("此套接字已关闭,发送失败");
            }
        }

        public void SendMsg(string clientId, string data, MsgType type)
        {
            ClientInfo client = clients[clientId];
            if (client.ClientSocket.Connected)
            {
                Send(client.ClientSocket, GetMsg(data, type, clientId));
            }
        }

        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                Console.WriteLine("取得回调信息的内容");
                // Retrieve the socket from the state object.
                Socket handler = (Socket)ar.AsyncState;
                if (handler.Connected)
                {
                    // Complete sending the data to the remote device.
                    int bytesSent = handler.EndSend(ar);
                    Console.WriteLine("Sent {0} bytes to client.", bytesSent);
                }
                else
                {
                    Console.WriteLine("连接已断开,发送失败 ");
                }

                //handler.Shutdown(SocketShutdown.Both);
                //handler.Close();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        #endregion



        internal void Close()
        {
            if (IsClose) return;
            allDone.Set();
            IsClose = true;
         //   this.m_Socket.Shutdown(SocketShutdown.Receive);
            m_listenThread.Abort();
            while (clients.Count > 0)
            {
                string key = clients.Keys.GetEnumerator().Current;
                Console.WriteLine("正在关闭" + key);
                try
                {
                    ClientInfo client = clients[key];

                    if (client.ClientSocket.Connected)
                    {
                        Send(client.ClientSocket, GetMsg("", MsgType.Exit, client.ClientId));
                        //client.ClientSocket.Close();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("客户端关闭失败" + ex.ToString());
                }
                clients.Remove(key);
            }
         //   this.m_Socket.Disconnect(false);
          
                this.m_Socket.Close();
        }
    }
}
